﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.IO;
using System.Collections;

namespace Open_MUD.Kernel.Interface.Client
{
    abstract class WizardBase
    {
        protected const String INICIO = "inicio";
        protected const String FIN = "fin";
        protected const String DEFERROR = "La opción introducida es incorrecta.";

        protected const string WIZBASE = "\\Config\\Wizard\\";
        protected XmlDocument handler;

        protected Cliente cliente;
        protected String name;
        protected ArrayList input = new ArrayList();

        protected String estadoActual;

        public WizardBase(Cliente c, String wizname)
        {
            cliente = c;
            this.name = wizname;
            estadoActual = INICIO;
            handler = new XmlDocument();
            string filename = Directory.GetCurrentDirectory() + WIZBASE + wizname + ".xml";            
            if (File.Exists(filename))
            {
                handler.Load(filename);                
            }
            else
                throw new MudException("El fichero handler de wizard["+wizname+"] no existe");
        
        }

        virtual internal bool validar(String line) { return true; }
        virtual internal String extractKey(String line) { return line; }
        virtual internal bool hookValidarError(String line) { return true; } //true: Tratamiento por defecto. False: Tratamiento personalizado
        virtual internal void actualizarEstado(String key)
        {
            String newEstado = "";
            try
            {
                newEstado = handler.SelectSingleNode("wizard/estado[@name='" + estadoActual + "']/targets/target[@key='" + key + "']").InnerText;
            }
            catch (Exception excpt)
            {
                try
                {
                    newEstado = handler.SelectSingleNode("wizard/estado[@name='" + estadoActual + "']/targets/target[@key='*']").InnerText;
                }
                catch (Exception excpt2)
                {
                    throw new MudException("Error en " + name + " estado:" + estadoActual + " key: " + key);
                }
            }
            if ( newEstado.Equals("") )
                throw new MudException("Nuevo estado vacío en " + name + " estado:" + estadoActual + " key: " + key);

            estadoActual = newEstado;
        }

        virtual internal void processLine(String key,String line)
        { 
        }

        private void pintarDescripcion(String key)
        {
            try //pintamos la descripcion del estado actual
            {
                String descripcion = handler.SelectSingleNode("wizard/estado[@name='" + estadoActual + "']/descripcion").InnerText;
                cliente.render(descripcion);
            }
            catch (Exception excpt)
            {
                try
                {   // Probamos a ver si es un nodo sin descripcion
                    handler.SelectSingleNode("wizard/estado[@name='" + estadoActual + "']/ignorardescripcion");
                }
                catch (Exception excpt2)
                {  // error al recoger la descripcion
                    new MudException("[WizardBase:tratar] estado:" + estadoActual + " key:" + key + " Error en la descripcion del wizard.");
                }
            }
        }

        internal void tratar(string line)
        {
            try
            {
                if (validar(line)) // tratamiento de recogida de datos del wizard
                {
                    //log del historial
                    input.Add(new String[2] { estadoActual, line });

                    // tratamiento para recoger el "key" que se utilizará en el autómata. Por defecto, la entrada del usuario
                    String key = extractKey(line);

                    //pintamos la descripcion
                    pintarDescripcion(key);

                    //ejecutar lo que se quiera en cada estado, según la entrada del usuario
                    processLine(key, line);

                    //procesamiento despues de pintar la descripcion
                    extraDesc(line);

                    //avanzamos en el automata de estados
                    actualizarEstado(key);

                    //gestión de fin del wizard
                    if (estadoActual.Equals(FIN))
                    {
                        cliente.resetWizard();
                        endWizard();
                    }
                }
                else
                {
                    if (hookValidarError(line))
                        cliente.render(DEFERROR);
                }
            }
            catch (MudException mudexcpt)
            {
                cliente.render(mudexcpt.Message);
            }
        }
        
        virtual internal void endWizard()
        {
            return;
        }

        virtual internal void extraDesc(String line)
        {
            return;
        }
    }
}
